// 本文件学习 go 语言自带算法加密库的一些包

package main

import (
	"bytes"
	"crypto/aes" // AES
	"crypto/cipher"
	"crypto/rand" //rand包实现了用于加解密的更安全的随机数生成器，主要用来生成随机加密串的
	"crypto/sha256"
	"encoding/base64"
	"encoding/binary"
	"math/big"
	r "math/rand"
	"time"

	/*
		"crypto/des" //DES
		"crypto/dsa" //FIPS 186-3定义的数字签名算法（Digital Signature Algorithm）
		"crypto/ecdsa" //ecdsa包实现了椭圆曲线数字签名算法
		"crypto/elliptic"  //elliptic包实现了几条覆盖素数有限域的标准椭圆曲线。
		"crypto/hmac" //hmac包实现了U.S. Federal Information Processing Standards Publication 198规定的HMAC（加密哈希信息认证码）。
						//HMAC是使用key标记信息的加密hash。接收者使用相同的key逆运算来认证hash。
						//出于安全目的，接收者应使用Equal函数比较认证码：

		"crypto/md5"
		"crypto/rc4"
		"crypto/rsa"
		"crypto/sha1"
		"crypto/sha256"
		"crypto/sha512"
		"crypto/subtle"
		"crypto/tls"
		"crypto/x509"
		"crypto/x709/pkix"
	*/
	"fmt"
	"log"
)

func main() {
	// fmt.Println("test crypto")
	// testAES()
	testRand()
	//testSha256()
	//testHC()
}

// test AES
func testAES() {
	d := []byte("hello,ase")
	key := []byte("thisisakey123456")
	//参数key为密钥，长度只能是16、24、32字节，用以选择AES-128、AES-192、AES-256。
	if len(key) != 16 {
		fmt.Println("invalid key", len(key))
		//return
	}

	x1, err := encryptAES(d, key)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Printf("原数据:%s  \n加密后:%s\n", string(d), string(x1))

	x2, err := decryptAES(x1, key)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println("解密后:", string(x2))
}

func encryptAES(src []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	// AES 加密的数据块大小不够，需要填充垃圾数据
	src = padding(src, block.BlockSize())
	blockMode := cipher.NewCBCEncrypter(block, key)
	blockMode.CryptBlocks(src, src)
	return src, nil
}

// 解密
func decryptAES(src []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockMode := cipher.NewCBCDecrypter(block, key)
	blockMode.CryptBlocks(src, src)
	src = unpadding(src)
	return src, nil
}

// 填充数据
func padding(src []byte, blockSize int) []byte {
	padNum := blockSize - len(src)%blockSize
	pad := bytes.Repeat([]byte{byte(padNum)}, padNum)
	return append(src, pad...)
}

// 去掉填充数据
func unpadding(src []byte) []byte {
	n := len(src)
	unPadNum := int(src[n-1])
	return src[:n-unPadNum]
}

func testRand() {
	n, err := rand.Int(rand.Reader, big.NewInt(128))
	if err == nil {
		fmt.Println("rand.int:", n, n.BitLen())
	}
	p, err := rand.Prime(rand.Reader, 5)
	if err == nil {
		fmt.Println("rand.Prime：", p)
	}
	//3、Read
	b := make([]byte, 16)
	m, err := rand.Read(b)
	if err == nil {
		fmt.Println("rand.Read：", b[:m])
		fmt.Println("rand.Read：", base64.URLEncoding.EncodeToString(b))
	}
	fmt.Println("生成区间[10,100]内的随机数")
	r.Seed(time.Now().UnixNano())
	for {
		index := r.Intn(4)
		fmt.Println("随机值为", index)
		if index == 0 || index == 4 {
			break
		}
	}

}

func testSha256() {

	d := []byte("hello sha256")

	x := sha256.Sum256(d)
	fmt.Printf("sha256Result: %x\n", x)

	d = []byte("hellobsha256")
	fmt.Printf("%x\n", sha256.Sum256(d))
}

// 测试哈希碰撞
func testHC() {
	d1 := []byte("apple")
	d2 := []byte("banana")

	x1 := sha256.Sum256(d1)
	i := 0
	for {
		d2 = append(d2, intToBytes(i)...)
		x2 := sha256.Sum256(d2)
		if x1 == x2 {
			fmt.Println("HC Done")
		}
		i++
		if i == 1000 {
			fmt.Printf("%x HC IS HARD %x\n", x1, x2)
			break
		}
		fmt.Println(i)
	}
}

func intToBytes(n int) []byte {
	data := int64(n)
	bytebuf := bytes.NewBuffer([]byte{})
	binary.Write(bytebuf, binary.BigEndian, data)
	return bytebuf.Bytes()
}
